//
//  FriendsSourceListElement.m
//  SolarSeek
//
//  Created by Erick Fejta on 05/06/01.
//  Copyright 2005 __MyCompanyName__. All rights reserved.
//

#import "FriendsSourceListElement.h"
#import "Peers.h"
#import "ApplicationDefaults.h"
#import "SolarSeekApplication.h"
#import "SolarSeekEngine.h"

FriendsSourceListElement *SharedFriendsSourceListElement = nil;

void *ObservePicture;

@interface FriendsSourceListElement (Private)
+ (BOOL)isFriend:(Peer *)peer;
@end

@implementation FriendsSourceListElement

+ (Peer *)loadPeerAtPath:(NSString *)path {
	path = [path stringByExpandingTildeInPath];
	id o = [[[NSKeyedUnarchiver unarchiveObjectWithFile:path] retain] autorelease];
	return o;
}

+ (void)loadPeerNamed:(NSString *)name {
	NSString *dir = [@"~/Library/Application Support/SolarSeek/" stringByExpandingTildeInPath];
	NSString *file = [dir stringByAppendingPathComponent:[name stringByAppendingString:@".friend.plist"]];
	if([[NSFileManager defaultManager] fileExistsAtPath:file] && 
			[[NSFileManager defaultManager] fileExistsAtPath:
				[[[file stringByDeletingPathExtension] stringByDeletingPathExtension] stringByAppendingPathComponent:@"browse.plist"]]==NO ) {
		[self loadPeerAtPath:file];
	}			
	else if([[NSFileManager defaultManager] fileExistsAtPath:file])
		NSLog(@"Skipping because %@ has a matching browse file.",file);
}

- (void)setup {
	[NSThread detachNewThreadSelector:@selector(setupInBackground) toTarget:self withObject:nil];
}

- (void)setupInBackground {
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	if([NSApp engine]==nil) {
		[self performSelector:@selector(setup) withObject:nil afterDelay:0.01];
	}
	else {
		NSArray *friends = [[NSUserDefaults standardUserDefaults] stringArrayForKey:SolarSeekDefaultFriends];
		NSEnumerator *e = [friends objectEnumerator];
		NSString *name;
		[self willChangeValueForKey:@"participants"];
		while(name = [e nextObject]) {
			[FriendsSourceListElement loadPeerNamed:name];			
			Peer *p = [[NSApp engine] peerNamed:name];
			[p addPrivileges:PeerPrivilegesFriend];
			[[NSApp engine] watchPeer:p];
			[peersFriend addObject:p];
			[p addObserver:self forKeyPath:@"availability" options:nil context:nil];
			[p addObserver:self forKeyPath:@"picture" options:nil context:ObservePicture];
			[p addObserver:self forKeyPath:@"countFiles" options:nil context:ObservePicture];
			[p addObserver:self forKeyPath:@"note" options:nil context:ObservePicture];
			[p addObserver:self forKeyPath:@"comment" options:nil context:ObservePicture];
		}
		[self didChangeValueForKey:@"participants"];
	}
	[pool release];
}

- (id)initWithView:(NSView *)view {
	if(self = [super initWithView:view]) {
		SharedFriendsSourceListElement = self;
		peersFriend = [[NSMutableArray alloc] init];
		[self performSelector:@selector(setup) withObject:nil afterDelay:0.5];
		online = 0;
	}
	return self;
}

- (void)dealloc {
	[peersFriend release];
	[super dealloc];
}

- (NSArray *)participants { return peersFriend; }

- (NSArray *)participantsWithAvailability:(Availability)avail { 
	NSMutableArray *ma = [NSMutableArray arrayWithCapacity:[peersFriend count]];
	NSEnumerator *e = [peersFriend objectEnumerator];
	Peer *p;
	while(p = [e nextObject]) {
		if([p availability] == avail) {
			[ma addObject:p];
		}
	}
	return ma;
}


- (NSString *)titleWindow { return @"Friend List"; }


- (NSString *)name { 
	unsigned countonline = [[self participantsWithAvailability:AvailabilityOnline] count]; 
	unsigned count = [[self participants] count];
	NSString *result = [NSString stringWithFormat:@"Friends (%d/%d)", countonline, count];
	return result;
}

+ (BOOL)savePeerInForeground:(Peer *)peer toPath:(NSString *)path {
	NSAssert(peer,@"Must save a non-null peer.");
	return [NSKeyedArchiver archiveRootObject:peer toFile:path];
}

+ (void)savePeerInForeground:(Peer *)peer {
	NSAssert(peer,@"Must save a non-null peer.");
	NSString *dir = [@"~/Library/Application Support/SolarSeek/" stringByExpandingTildeInPath];
	NSString *path = [dir stringByAppendingPathComponent:[[peer name] stringByAppendingString:@".browse.plist"]];
	if([self savePeerInForeground:peer toPath:path]) {	
		if([self isFriend:peer]) {
			NSFileManager *fm = [NSFileManager defaultManager];
			NSString *bpath = [dir stringByAppendingPathComponent:[[peer name] stringByAppendingString:@".friend.plist"]];
			[fm linkPath:path toPath:bpath handler:nil];
		}
	}
	else {
		[NSApp appendLogWithHeader:@"ERROR" 
			HTML:[NSString stringWithFormat:@"Unable to save %@'s info to %@",peer,path] 
			type:LogTypeError];
	}
}

+ (BOOL)isFriend:(Peer *)peer {
	NSArray *friends = [[NSUserDefaults standardUserDefaults] stringArrayForKey:SolarSeekDefaultFriends];
	return [friends containsObject:[peer name]];
}

- (NSImage *)icon { return [NSImage imageNamed:@"sourcelistFriends"]; }

- (void)addFriend:(Peer *)peer {
	NSArray *friends = [[NSUserDefaults standardUserDefaults] stringArrayForKey:SolarSeekDefaultFriends];
	if(friends == nil) 
		friends = [NSArray array];
	if([friends containsObject:[peer name]]==NO) {
		[self savePeer:peer];
		[peer addPrivileges:PeerPrivilegesFriend];
		friends = [friends arrayByAddingObject:[peer name]];
		[self willChangeValueForKey:@"participants"];
		[[NSApp engine] watchPeer:peer];
		[peersFriend addObject:peer];
		[peer addObserver:self forKeyPath:@"availability" options:nil context:nil];
		[peer addObserver:self forKeyPath:@"picture" options:nil context:ObservePicture];
//		[peer addObserver:self forKeyPath:@"countFiles" options:nil context:ObserveFiles];
		[peer addObserver:self forKeyPath:@"comment" options:nil context:ObservePicture];
		[peer addObserver:self forKeyPath:@"note" options:nil context:ObservePicture];
		[self didChangeValueForKey:@"participants"];
		NSUserDefaultsController *nudc = [NSUserDefaultsController sharedUserDefaultsController];
		[[nudc values] setValue:friends forKeyPath:SolarSeekDefaultFriends];
		[[NSUserDefaults standardUserDefaults] setValue:friends forKey:SolarSeekDefaultFriends];
		[self refresh];
	}
}
	
- (void)removeFriend:(Peer *)peer {
	NSArray *friends = [[NSUserDefaults standardUserDefaults] stringArrayForKey:SolarSeekDefaultFriends];
	if(friends && [friends containsObject:[peer name]]==YES) {
		NSMutableArray *f = [NSMutableArray arrayWithArray:friends];
		[f removeObject:[peer name]];
		[self willChangeValueForKey:@"participants"];
		// BUG: I don't know if it's exactly a bug, but as a security measure, I don't like the user name being part of a filename.
		NSString *file = [[NSString stringWithFormat:@"~/Library/Application Support/SolarSeek/%@.friend.plist", [peer name]] stringByExpandingTildeInPath];
		[[NSFileManager defaultManager] removeFileAtPath:file handler:nil];
		[peersFriend removeObject:peer];
		[peer removeObserver:self forKeyPath:@"availability"];
		[self didChangeValueForKey:@"participants"];
		NSUserDefaultsController *nudc = [NSUserDefaultsController sharedUserDefaultsController];
		[[nudc values] setValue:f forKeyPath:SolarSeekDefaultFriends];
		[nudc save:self];
		[[NSUserDefaults standardUserDefaults] setObject:f forKey:SolarSeekDefaultFriends];
		[self refresh];
	}
}
	
- (void)setSelected:(BOOL)selected {
	[super setSelected:selected];
	online = [[ self participantsWithAvailability:AvailabilityOnline] count];
}

- (void)update {
	[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(update) object:nil];
	unsigned newonline = [[self participantsWithAvailability:AvailabilityOnline] count];
	[self refreshAndRequestAttention:newonline > online];
	online = newonline>online?newonline:online;
}

- (void)savePeerBackground:(Peer *)peer {
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	[NSThread setThreadPriority:0.1];
	@synchronized(peer) {
		[FriendsSourceListElement savePeerInForeground:peer];
	}
	[pool release];
}

- (void)savePeer:(Peer *)peer {
	[NSThread detachNewThreadSelector:@selector(savePeerBackground:) toTarget:self withObject:peer];
}

- (void)savePeerToPathInBackground:(id)array {
	Peer *peer = [array objectAtIndex:0];
	NSString *path = [array objectAtIndex:1];
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	[NSThread setThreadPriority:0.1];
	@synchronized(peer) {
		[FriendsSourceListElement savePeerInForeground:peer toPath:path];
	}
	[pool release];
}
- (void)savePeer:(Peer *)peer toPath:(NSString *)path {
	BOOL dir;
	path = [path stringByExpandingTildeInPath];
	NSAssert1([[NSFileManager defaultManager] fileExistsAtPath:[path stringByDeletingLastPathComponent] isDirectory:&dir],@"The folder does not exist",[path stringByDeletingPathExtension]);
	NSAssert1(dir,@"%@ is not a folder",[path stringByDeletingPathExtension]);
	NSArray *a = [[NSArray alloc] initWithObjects:peer,path,nil];
	[NSThread detachNewThreadSelector:@selector(savePeerToPathInBackground:) toTarget:self withObject:a];
	[a release];
}

void *ObservePicture = (void *)111;

- (void)scheduleUpdate {
	[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(update) object:nil];
	[self performSelector:@selector(update) withObject:nil afterDelay:1.0];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
	[self performSelectorOnMainThread:@selector(scheduleUpdate) withObject:nil waitUntilDone:NO];
	if([object picture] && context==ObservePicture) {
		[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(saveFriend:) object:object];
		[self performSelector:@selector(savePeer:) withObject:object afterDelay:3.0];
	}
}

+ (FriendsSourceListElement *)friendsSourceListElementShared { return SharedFriendsSourceListElement; }

- (void)addElement:(SourceListElement *)element {
	[super addElement:element];
	[NSApp updateSourceList];
	[NSApp expandSourceListElement:self];
}

- (void)removeElement:(SourceListElement *)element {
	[super removeElement:element];
	[NSApp updateSourceList];
}


@end
